package com.bigfans.cartservice.service.impl;

import com.bigfans.cartservice.api.clients.InventoryServiceClient;
import com.bigfans.cartservice.api.clients.PricingServiceClient;
import com.bigfans.cartservice.dao.CartItemDAO;
import com.bigfans.cartservice.exception.ProductOffSaleException;
import com.bigfans.cartservice.exception.StockInsufficientException;
import com.bigfans.cartservice.model.*;
import com.bigfans.cartservice.service.CartService;
import com.bigfans.cartservice.service.ProductService;
import com.bigfans.cartservice.service.ProductSpecService;
import com.bigfans.framework.dao.BaseServiceImpl;
import com.bigfans.framework.utils.CollectionUtils;
import com.bigfans.model.dto.cart.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;

/**
 * 购物车服务类
 * 
 * @author lichong
 *
 */
@Service(CartServiceImpl.BEAN_NAME)
public class CartServiceImpl extends BaseServiceImpl<CartItem> implements CartService {

	public static final String BEAN_NAME = "cartService";

	@Autowired
	private ProductService productService;
	@Autowired
	private ProductSpecService productSpecService;
	@Autowired
	private PricingServiceClient pricingServiceClient;
	@Autowired
	private InventoryServiceClient inventoryServiceClient;

	private CartItemDAO cartItemDAO;

	@Autowired
	public CartServiceImpl(CartItemDAO cartItemDAO) {
		super(cartItemDAO);
		this.cartItemDAO = cartItemDAO;
	}

	/**
	 * 获取用户的购物车信息
	 * 
	 * @param userId
	 * @return
	 * @throws Exception
	 */
	public Cart myCart(String userId) throws Exception {
		return myCart(userId, null, null);
	}

	@Override
	@Transactional(readOnly = true)
	public Cart cartSummary(String userId, Long limit) throws Exception {
		List<CartItem> cartItems = cartItemDAO.listByUser(userId, 0L, limit);
		Cart cart = this.populateCart(cartItems);
		return cart;
	}

	@Override
	@Transactional(readOnly = true)
	public Cart myCart(String userId, Long start, Long pagesize) throws Exception {
		List<CartItem> cartItems = cartItemDAO.listByUser(userId, start, pagesize);
		if(CollectionUtils.isEmpty(cartItems)){
			return new Cart();
		}
		Cart cart = this.populateCart(cartItems);
		return cart;
	}

	@Override
	@Transactional(readOnly = true)
	public Cart populateCart(List<CartItem> cartItems) throws Exception {
		CartPricingDto cartPricingDto = new CartPricingDto();
		cartPricingDto.setUserId(cartItems.get(0).getUserId());
		for(CartItem cartItem : cartItems){
			CartItemDto itemDto = new CartItemDto(cartItem.getProdId() , cartItem.getQuantity());
			cartPricingDto.addCartItem(itemDto);
		}

		CartPricingResultDto calculateResultDto = pricingServiceClient.calculateCart(cartPricingDto);

		for (CartItem item : cartItems) {

			String prodId = item.getProdId();
			// 获取商品信息
			Product product = productService.getDetailById(prodId);
			item.setProdName(product.getName());
			item.setProdImg(product.getImagePath());
			item.setSpecList(product.getSpecList());
			item.setWeight(product.getWeight());

			CartItemPricingResultDto pricingDto = calculateResultDto.getPrice(item.getProdId());
			item.setOriginalPrice(pricingDto.getOriginalPrice());
			item.setPrice(pricingDto.getPrice());
			item.setOriginalSubTotal(pricingDto.getOriginalSubTotal());
			item.setSubTotal(pricingDto.getSubtotal());


            List<CartItemPromotionDto> promotions = calculateResultDto.getPromotion(prodId);
            if(CollectionUtils.isNotEmpty(promotions)){
                List<Promotion> promotionList = new ArrayList<>();
                promotions.forEach((promotionDto) -> {
                    Promotion promotion = new Promotion();
					promotion.setId(promotionDto.getPromotionId());
                    promotion.setName(promotionDto.getPromotionName());
                    promotion.setSelectable(promotionDto.isSelectable());
                    promotion.setSelected(promotionDto.isSelected());
                    promotionList.add(promotion);
                });
                item.setPromotionList(promotionList);
            }

            List<CartItemCouponDto> coupons = calculateResultDto.getCoupon(prodId);
            if(CollectionUtils.isNotEmpty(coupons)){
                List<Coupon> couponList = new ArrayList<>();
                coupons.forEach((couponDto) -> {
                    Coupon coupon = new Coupon();
                    coupon.setName(couponDto.getCouponName());
                    coupon.setSelectable(couponDto.isSelectable());
                    coupon.setSelected(couponDto.isSelected());
                    couponList.add(coupon);
                });
                item.setCouponList(couponList);
            }
		}
		Cart cart = new Cart();
		cart.setItems(cartItems);
		return cart;
	}

	/**
	 * 合并购物车
	 * 
	 * @throws Exception
	 */
	public void mergeMyCart(String userId, Cart tempCart) throws Exception {
		Cart dbCart = myCart(userId);
		List<CartItem> tempItems = tempCart.getItems();
		if (CollectionUtils.isEmpty(tempItems)) {
			return;
		}
		Map<String, CartItem> dbitemMap = new HashMap<String, CartItem>();
		for (CartItem dbItem : dbCart.getItems()) {
			dbitemMap.put(dbItem.getProdId(), dbItem);
		}
		List<CartItem> itemToCreate = new ArrayList<CartItem>();
		for (CartItem tempItem : tempItems) {
			CartItem civo = dbitemMap.get(tempItem.getProdId());
			// 如果db中不存在,那么创建一条记录,否则更新购买数量
			if (civo == null) {
				tempItem.setUserId(userId);
				itemToCreate.add(tempItem);
			} else {
				// 更新购买数量为临时购物车中的数量
				civo.setQuantity(tempItem.getQuantity());
				update(civo);
			}
		}
		if (!CollectionUtils.isEmpty(itemToCreate)) {
			batchCreate(itemToCreate);
		}
	}

	/**
	 * 添加购物项
	 * 
	 * @param userId
	 * @throws Exception
	 */
	@Transactional
	public void addItem(String userId, String pid, Integer quantity) throws Exception {
		// 添加购物项
		Long count = cartItemDAO.countByUser(userId, pid);
		if (count > 0) {
			// 如果已经添加商品到购物车，增加数量
			cartItemDAO.increaseByUser(userId, pid, quantity);
		} else {
			// 创建一条记录
			CartItem cartItem = new CartItem();
			cartItem.setUserId(userId);
			cartItem.setProdId(pid);
			cartItem.setQuantity(quantity);
			cartItem.setIsSelected(true);
			super.create(cartItem);
		}
	}

	/**
	 * 移除购物项
	 * 
	 * @param userId
	 * @param id
	 *            购物车项id
	 * @throws Exception
	 */
	@Transactional
	public void removeItem(String userId, String id) throws Exception {
		cartItemDAO.deleteMyItemsById(userId, new String[] { id });
	}

	@Transactional
	public void removeItems(String userId, String[] ids) throws Exception {
		cartItemDAO.deleteMyItemsById(userId, ids);
	}

	@Transactional
	public void removeCart(String userId) throws Exception {
		cartItemDAO.deleteMyItemsById(userId, null);
	}

	@Override
	public void removeSelectedItems(String userId) throws Exception {
		cartItemDAO.deleteSelectedItems(userId);
	}

	@Transactional
	public void updateQuantity(String uid, String prodId, int quantity) throws Exception {
		try{
			CompletableFuture<Integer> future = inventoryServiceClient.getSurplusStock(prodId);
			CartItem cartItem = cartItemDAO.loadByUser(uid, prodId);
			if (!cartItem.isProductOnSale()) {
				throw new ProductOffSaleException("该商品已经下架");
			}

			// 查询库存,如果库存不足抛出异常
			Integer stock = future.get();
			if (stock == null || stock < quantity) {
				throw new StockInsufficientException("该商品库存不足");
			}

			// 更新购买数量
			CartItem example = new CartItem();
			example.setId(cartItem.getId());
			example.setQuantity(quantity);
			super.update(example);
		}catch (Exception e){
			throw new Exception(e);
		}
	}

	@Override
	public Integer sumMyCart(String userId) throws Exception {
		Long sum = cartItemDAO.sumByUser(userId);
		return sum == null ? 0 : sum.intValue();
	}

	@Override
	public Integer countByProduct(String uid, String pid) throws Exception {
		return null;
	}

	@Override
	@Transactional(readOnly = true)
	public List<CartItem> getSelectedItems(String userId) throws Exception {
		return cartItemDAO.getItems(userId, true);
	}

	@Override
	public List<CartItem> getItems(String userId) throws Exception {
		return cartItemDAO.getItems(userId, false);
	}

	@Override
	@Transactional
	public void select(String userId, String productId) throws Exception {
		cartItemDAO.changeItemSelectStatus(userId, productId, true);
	}

	@Override
	@Transactional
	public void selectAll(String userId) throws Exception {
		cartItemDAO.changeAllItemsSelectStatus(userId, true);
	}

	@Override
	@Transactional
	public void cancel(String userId, String productId) throws Exception {
		cartItemDAO.changeItemSelectStatus(userId, productId, false);
	}

	@Override
	@Transactional
	public void cancelAll(String userId) throws Exception {
		cartItemDAO.changeAllItemsSelectStatus(userId, false);
	}

}
